跳到主要内容

Go 内嵌静态文件之 embed 包

embed 包是一个用来访问嵌入文件的包,先来说下为啥需要这个包

Golang 编译文件时并不会把配置文件之类的静态文件打包编译到二进制文件中,所以在 1.16 以前需要把静态资源打包成二进制文件需要使用第三方工具 go-bindata、statik、togo 等库,在 1.16 之后官方提供的这个 embed 包就是用来处理这事的

简单使用方式

例如当前项目目录上有个 config.yml 文件需要打包进来

import (
_ "embed"
)

//go:embed config.yml
var content string

func main() {
fmt.Println(content)
}

就能将这个 config.yml 文件的内容读取到这个 content 变量里面来了

Go 能够允许嵌入的变量类型有如下三种:

变量类型说明
[]byte用于存储二进制形式的数据,比如图片、富媒体等。
string用于存储 UTF-8 编码的字符串。
embed.FS用于嵌入多个文件和目录的结构。

go embed 仅能嵌入当前目录及其子目录,无法嵌入上层目录。同时也不支持软链接。go emebd 禁止嵌入如 .git .svn 这些目录,官方认为这些目录不属于 package 的一部分,如果嵌入则会在编译时报错。

嵌入多个文件:

import (
"embed"
)

//go:embed *.tmpl
var FS embed.FS

嵌入多个目录

.
├── css
│ └── sandbox.css
└── js
└── sandbox.js
import (
"embed"
)

//go:embed css js
var FS embed.FS

func main() {
fmt.Println(content)
}

然后读取这个 embed.FS 可以使用它提供的 ReadFile 方法

//go:embed config.yml
var FS embed.FS

func main() {
if bytes, err := FS.ReadFile("config.yml"); err != nil {
fmt.Println("Error reading config")
} else {
fmt.Println(string(bytes))
}
}

补充内容,读取 yml 文件的内容

host: localhost:3306
username: 'juan'
password: '123456'

使用 yaml 包解析 yml 文件

package main

import (
"embed"
"fmt"

"gopkg.in/yaml.v2"
)

//定义conf类型
//类型里的属性,全是配置文件里的属性
type conf struct {
Host string `yaml: "host"`
User string `yaml: "username"`
Pwd string `yaml: "password"`
}

//go:embed config.yml
var content embed.FS

func main() {
var c conf
bytes, err := content.ReadFile("config.yml")
if err != nil {
fmt.Println("Error reading config.yml")
}
yaml.Unmarshal(bytes, &c)

fmt.Printf("%v", c)
}

静态服务器

20220920152523

嵌入文件

// cli/embed.go
package cli

import (
"embed"
_ "embed"
)

var (
//go:embed assets
Staticfiles embed.FS

//go:embed index.html
IndexPage []byte

//go:embed vite.svg
Iconf []byte
)

Gin 加载

r := gin.Default()
fe, err := fs.Sub(cli.Staticfiles, "assets") // 多了一级目录
r.StaticFS("/assets", http.FS(fe))
r.GET("/", func(c *gin.Context) {
c.Header("content-type", "text/html;charset=utf-8")
c.String(200, string(cli.IndexPage))
})

s := &http.Server{
Addr: config.GlobalConfigVar.GetMWAddr(),
Handler: handlers.CORS(
handlers.AllowedMethods([]string{"GET", "POST", "PUT"}),
handlers.AllowedHeaders([]string{"Accept", "Accept-Language", "Content-Type", "Content-Language", "Origin"}),
handlers.AllowedOrigins([]string{"*"}),
)(r),
}

注意!!! 这里多了一级目录

References

道理我都懂,但 go embed 究竟该怎么用?